﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ProgNetComponentsDx.Tasks;
using System.Threading.Tasks;
using BhServer.Comunication;

namespace BhServer
{
    public class UpdateServerService : IUpdateServerService, IChatService
    {
        #region static
        public static event EventHandler UsersChanged;

        public static TaskScheduler TaskScheduler { get; set; }

        private static void OnUsersChanged(object sender)
        {
            if (UsersChanged != null)
            {
                UsersChanged(sender, EventArgs.Empty);
            }
        }

        static object obj = new object();
        static Dictionary<int, User> users = new Dictionary<int, User>();
        public static List<User> GetUsersList()
        {
            return users.Values.ToList();
        }

        static int index = 0;
        #endregion

        #region IUpdateServerService
        public Version GetLatestVersion()
        {
            return new Version("1.3.2");
        }
        public void Connect(int userId)
        {
            lock (obj)
            {
                if (users.ContainsKey(userId))
                {
                    User u = users[userId];
                    u.UpdateServerServiceCallback = OperationContext.Current.GetCallbackChannel<IUpdateServerServiceCallback>();
                }
            }
        }
        #endregion

        private class MonitorTask : ProgNetComponentsDx.Tasks.BaseTask
        {
            public MonitorTask(User u)
            {
                User = u;
            }
            public User User { get; private set; }
            
            protected override ProgNetComponentsDx.Tasks.TaskStatus PerformTask(System.Threading.CancellationToken token)
            {
                while (true)
                {
                    token.ThrowIfCancellationRequested();
                    lock (obj)
                    {
                        if (users.ContainsKey(User.UserId))
                        {
                            try
                            {
                                if (User.UpdateServerServiceCallback != null)
                                    User.UpdateServerServiceCallback.Notify();
                            }
                            catch
                            {
                                users.Remove(User.UserId);
                                OnUsersChanged(User);
                                return ProgNetComponentsDx.Tasks.TaskStatus.Finished;
                            }
                        }
                        else
                        {
                            return ProgNetComponentsDx.Tasks.TaskStatus.Finished;
                        }
                    }
                    for (int i = 0; i < 10; i++)
                    {
                        token.ThrowIfCancellationRequested();
                        System.Threading.Thread.Sleep(100);
                    }
                }

            }
        }
        
        #region IChatService
        public int LogIn(string name)
        {
            int id = index++;
            try
            {
                User u = new User(id, name);
                u.Task = new MonitorTask(u);
                u.Task.Scheduler = TaskScheduler;

                u.ChatServiceCallback = OperationContext.Current.GetCallbackChannel<IChatServiceCallback>();
                lock (obj)
                {
                    users.Add(id, u);
                }
                u.Task.Run();
                OnUsersChanged(u);
            }
            catch
            {
                return -1;
            }

            return id;
        }

        public void LogOut(int userId)
        {
            lock (obj)
            {
                if (users.ContainsKey(userId))
                {
                    User u = users[userId];
                    u.Task.Cancel();
                    users.Remove(userId);
                    OnUsersChanged(u);
                }
            }
        }

        public void SendMessage(int sender, int receiver, string message)
        {
            throw new NotImplementedException();
        }

        public ChatUser[] GetUsers()
        {
            return GetUsersList().ToArray();
        }

        public void Beep()
        {

        }
        #endregion
    }

    public class User : ChatUser
    {
        public User(int userId, string name)
            : base(userId, name)
        {

        }

        public IUpdateServerServiceCallback UpdateServerServiceCallback { get; set; }
        public IChatServiceCallback ChatServiceCallback { get; set; }

        public BaseTask Task { get; set; }
    }
}
